; ******************************************************************************
; * demo13.asm
; * LLP STUDIO SVP Peng
; * V1.0
; * 2023-08-25
; * 利用外部中断INT0，K3单键（P3.2）控制花样流水灯
; * 特意指明启用INT0中断
; * 与按钮扫描定义处理的差别是：按钮必须不断地扫描判断，发生之后进行处理；
; * 而中断允许之后，无需扫描发生即转
; * 与单键多模式流水实验比较
; ******************************************************************************

ORG 0
JMP Start
ORG 03H   ; INT0中断向量（起始点必须）
JMP Int_0  ; 执行Int0中断子程序（实际的中断入口）

Start:
MOV IE, #10000001B  ; 打开总开关与EX0分路开关
MOV SP, #30H  ; 设定堆栈地址（栈顶指针）
SETB IT0  ; 采用下降沿触发信号（负缘）
MOV A, #0  ; 将ACC清零

Loop:
MOV P2, A  ; 输出到LED
CALL Delay
CPL A  ; 将A的内容反相
JMP Loop  ; 形成循环

Int_0:  ; 中断子程序定义
; 防止中断与主程序寄存器冲突，先入栈，后子程序结束再出栈
PUSH ACC  ; 累加器入栈时不能用简称A
PUSH PSW  ; 将程序状态控制字入栈
SETB RS0  ; 切换到RB1（寄存器组1）

MOV R0, #3  ; 设定三次循环
IntLoop0:
MOV A, #0FEH  ; 单灯左移初始值
MOV R1, #8  ; 设定8次左移
IntLoop1:
MOV P2, A  ; 输出LED到P2口
CALL Delay  ; 调用延时子程序
RL A  ; 将A的内容左移
DJNZ R1, IntLoop1  ; 8次左移
DJNZ R0, IntLoop0  ; 3次循环
; 栈是一种后进先出（LIFO）的数据结构
POP PSW
POP ACC  ; 累加器出栈时不能用简称A
RETI  ; 返回主程序

Delay:
MOV R7, #200
D1:
MOV R6, #250
DJNZ R6, $
DJNZ R7, D1
RET

END
